﻿#region 引用
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
#endregion

namespace PControl
{
    /// <summary>
    /// 3DP喷墨打印监控动画控件
    /// </summary>
    public partial class PowderControl : UserControl
    {
        #region 带公共方法的私有字段
        /// <summary>
        /// 振镜的水平位置
        /// </summary>
        private float mirrorLocation=0f;
        /// <summary>
        /// 振镜 横 向极限位置 单位:mm
        /// </summary>
        private float mirrorMaxH = 300;
        /// <summary>
        /// 振镜 纵 向极限位置 单位:mm
        /// </summary>
        private float mirrorMaxZ = 300;
        /// <summary>
        /// 振镜的工作状态
        /// </summary>
        private WorkState mirrorState = WorkState.STOP;
        /// <summary>
        /// 铺粉辊的水平位置
        /// </summary>
        private float rollerLocation = 0f;
        /// <summary>
        /// 铺粉辊极限位置 单位:mm
        /// </summary>
        private float rollerMax=300;
        /// <summary>
        /// 铺粉辊直径 单位:mm
        /// </summary>
        private float rollerDiameter=30;
        /// <summary>
        /// 铺粉辊的工作状态
        /// </summary>
        private WorkState rollerState = WorkState.STOP;
        /// <summary>
        /// 铺粉方向
        /// </summary>
        private SpreadPowderDirection spreadDirection;
        /// <summary>
        /// 振镜移动速度 单位:mm/s
        /// </summary>
        private float mirrorSpeed;
        /// <summary>
        /// 振镜加速度 单位:mm/s^2
        /// </summary>
        private float mirrorAcc;
        /// <summary>
        /// 铺粉辊的水平移动速度 单位:mm/s
        /// </summary>
        private float rollerSpeed;
        /// <summary>
        /// 铺粉辊水平移动加速度 单位:mm/s^2
        /// </summary>
        private float rollerAcc;
        /// <summary>
        /// 铺粉厚度 单位:mm
        /// </summary>
        private float powderPly = 0.2f;
        /// <summary>
        /// 粉层纵向长度 单位:mm
        /// </summary>
        private float powderLength = 300f;
        /// <summary>
        /// 粉层横向宽度 单位:mm
        /// </summary>
        private float powderWidth = 300f;
        /// <summary>
        /// 粉量 单位:L
        /// </summary>
        private float powderQuantity = 50;
        /// <summary>
        /// 粉缸容量 单位:L
        /// </summary>
        private float powderCapacity = 50;
        /// <summary>
        /// 粉缸状态
        /// </summary>
        private PowderState powderState;
        /// <summary>
        /// 工作缸高度 单位:mm
        /// </summary>
        private float workingUrnHight = 500;
        /// <summary>
        /// 工作缸最大高度 单位:mm
        /// </summary>
        private float workingUrnMaxHight = 500;
        /// <summary>
        /// 工作缸最小高度 单位:mm
        /// </summary>
        private float workingUrnMinHight = 200;
        /// <summary>
        /// 振镜部分背景色
        /// </summary>
        private Color mirrorBack=System.Drawing.SystemColors.Control;
        /// <summary>
        /// 铺粉辊部分背景色
        /// </summary>
        private Color rollerBack = System.Drawing.SystemColors.Control;
        /// <summary>
        /// 粉缸部分背景色
        /// </summary>
        private Color powderBack = System.Drawing.SystemColors.Control;
        /// <summary>
        /// 工作缸部分背景色
        /// </summary>
        private Color workingUrnBack = System.Drawing.SystemColors.Control;
        /// <summary>
        /// 当前层是否打印完毕
        /// </summary>
        private bool isPrintFinished = false;
        #endregion

        #region 不带公共方法的私有字段
        /// <summary>
        /// 振镜背景宽度
        /// </summary>
        private Size preSize;
        private Size currentSize;
        private int mirrorBackWidth=184;
        private int rollerBackWidth = 160;
        private bool isMirrorStop = false;
        private Boolean isRollerStop = false;
        private bool isPowderUseup=false;
        private double rollerAngle = 0.0;
        /// <summary>
        /// 用于在控件大小改变时起标识作用，放置因两层调用致使某些属性改变两次
        /// </summary>
        private bool isSizeChangedOk = false;
        #endregion

        #region *** get and set ***
        [DefaultValue(0f)]
        [Browsable(false)]
        [Description("获取或设置振镜横向位置")]
        public float MirrorLocation
        {
            get { return mirrorLocation; }
            set
            {
                mirrorLocation = value;
                if (mirrorLocation > mirrorBackWidth)
                    mirrorLocation = mirrorBackWidth;
                else if (mirrorLocation < 0)
                    mirrorLocation = 0;
            }
        }
        [DefaultValue(300)]
        [Description("获取或设置振镜横向极限值 单位:mm")]
        public float MirrorMaxH
        {
            get { return mirrorMaxH; }
            set
            {
                mirrorMaxH = value;
                if (mirrorMaxH <= 0)
                    mirrorMaxH = 300;
            }
        }
        [DefaultValue(300)]
        [Description("获取或设置振镜纵向极限值 单位:mm")]
        public float MirrorMaxZ
        {
            get { return mirrorMaxZ; }
            set
            {
                mirrorMaxZ = value;
                if (mirrorMaxZ <= 0)
                    mirrorMaxZ = 300;
            }
        }
        [DefaultValue(WorkState.STOP)]
        [Description("获取或设置振镜的工作状态")]
        public WorkState MirrorState
        {
            get { return mirrorState; }
            set { mirrorState = value; }
        }
        [DefaultValue(0f)]
        [Browsable(false)]
        [Description("获取或设置铺粉辊水平位置")]
        public float RollerLocation
        {
            get { return rollerLocation; }
            set
            {
                rollerLocation = value;
                if (rollerLocation == float.NaN)
                {
                    rollerLocation = 0f;
                }
                if (rollerLocation > rollerBackWidth)
                    rollerLocation = rollerBackWidth;
                else if (rollerLocation < 0)
                    rollerLocation = 0;
            }
        }
        [DefaultValue(300)]
        [Description("获取或设置铺粉辊极限位置 单位:mm")]
        public float RollerMax
        {
            get { return rollerMax; }
            set
            {
                rollerMax = value;
                if (rollerMax <= 0)
                    rollerMax = 300;
            }
        }
        //public float RollerDiameter
        //{
        //    get { return rollerDiameter; }
        //    set { rollerDiameter = value; }
        //}
        [DefaultValue(WorkState.STOP)]
        [Description("获取或设置铺粉辊的工作状态")]
        public WorkState RollerState
        {
            get { return rollerState; }
            set { rollerState = value; }
        }

        [DefaultValue(SpreadPowderDirection.LEFT_TO_RIGHT)]
        [Description("获取或设置铺粉方向")]
        public SpreadPowderDirection SpreadDirection
        {
            get { return spreadDirection; }
            set 
            { 
                spreadDirection = value;
                switch (spreadDirection)
                {
                    case SpreadPowderDirection.LEFT_TO_RIGHT:
                        if (rollerSpeed > 0f)
                            rollerState = WorkState.WORK;
                        else if (rollerState < 0f)
                            rollerState = WorkState.BACK;
                        break;
                    case SpreadPowderDirection.RIGHT_TO_LEFT:
                        if (rollerSpeed > 0f)
                            rollerState = WorkState.BACK;
                        else if (rollerState < 0f)
                            rollerState = WorkState.WORK;
                        break;
                    case SpreadPowderDirection.BIDIRECTION:
                        rollerState = WorkState.WORK;
                        break;
                }
            }
        }
        
        [DefaultValue(0.0f)]
        [Description("获取或设置振镜移动速度 单位:mm/s")]
        public float MirrorSpeed
        {
            get { return mirrorSpeed; }
            set {
                mirrorSpeed = value;
                if (mirrorSpeed > 0.0001f)
                {
                    mirrorState = WorkState.WORK;
                    if (isMirrorStop)
                    {
                        startMirror();
                    }
                }
                else if (mirrorSpeed < -0.0001f)
                {
                    mirrorState = WorkState.BACK;
                    if (isMirrorStop)
                    {
                        startMirror();
                    }
                }
                else if (mirrorSpeed < 0.0001f && mirrorSpeed > -0.0001f && mirrorAcc < 0.0001f && mirrorAcc > -0.0001f)
                {
                    stopMirror();
                }
            }
        }

        [DefaultValue(0.0f)]
        [Description("获取或设置铺粉辊移动速度 单位:mm/s")]
        public float RollerSpeed
        {
            get { return rollerSpeed; }
            set
            {
                rollerSpeed = value;
                switch (spreadDirection)
                {
                    case SpreadPowderDirection.LEFT_TO_RIGHT:
                        if (rollerSpeed > 0.000f) 
                            rollerState = WorkState.WORK;
                        else if (rollerSpeed < -0.000f) rollerState = WorkState.BACK;
                        else if (rollerAcc < 0.0001f && rollerAcc > -0.0001f)
                        {
                            stopRoller();
                        }
                        break;
                    case SpreadPowderDirection.RIGHT_TO_LEFT:
                        if (rollerSpeed < 0.0001f) rollerState = WorkState.WORK;
                        else if (rollerSpeed > -0.0001f) rollerState = WorkState.BACK;
                        else if (rollerAcc < 0.0001f && rollerAcc > -0.0001f)
                        {
                            stopRoller();
                        }
                        break;
                    case SpreadPowderDirection.BIDIRECTION:
                        if (rollerSpeed > 0.0001f || rollerSpeed < -0.0001f) rollerState = WorkState.WORK;
                        else if (rollerAcc < 0.0001f && rollerAcc > -0.0001f)
                        {
                            stopRoller();
                        }
                        break;
                }
                if (rollerState != WorkState.STOP && isRollerStop)
                {
                    startRoller();
                }
            }
        }

        [DefaultValue(0f)]
        [Description("获取或设置振镜移动加速度 单位:mm/s^2")]
        public float MirrorAcc
        {
            get { return mirrorAcc; }
            set { 
                mirrorAcc = value;
                if (isMirrorStop)
                {
                    startMirror();
                }
            }
        }

        [DefaultValue(0f)]
        [Description("获取或设置铺粉辊移动加速度 单位:mm/s^2")]
        public float RollerAcc
        {
            get { return rollerAcc; }
            set 
            {
                rollerAcc = value;
                if (isRollerStop)
                {
                    startRoller();
                }
            }
        }

        [DefaultValue(0.2f)]
        [Description("获取或设置铺粉层厚度 单位:mm")]
        public float PowderPly
        {
            get { return powderPly; }
            set 
            { 
                powderPly = value; 
                if(powderPly<0)
                    powderPly=0.2f;
            }
        }
        
        [DefaultValue(300f)]
        [Description("获取或设置铺粉层纵向长度 单位:mm")]
        public float PowderLength
        {
            get { return powderLength; }
            set 
            {
                powderLength = value;
                if (powderLength < 0)
                    powderLength = 300f;
            }
        }
        
        [DefaultValue(300f)]
        [Description("获取或设置铺粉层横向宽度 单位:mm")]
        public float PowderWidth
        {
            get { return powderWidth; }
            set 
            {
                powderWidth = value;
                if (powderWidth < 0)
                    powderWidth = 300f;
            }
        }
        
        [DefaultValue(0)]
        [Description("获取或设置粉缸粉量 单位:L")]
        public float PowderQuantity
        {
            get { return powderQuantity; }
            set { 
                powderQuantity = value;
                if (powderQuantity < 0)
                    powderQuantity = 0;
                else if (powderQuantity > powderCapacity)
                    powderQuantity = powderCapacity;
                int rate = (int)(powderQuantity * 100 / powderCapacity);
                if (rate > 95)
                    powderState = PowderState.FULL;
                else if (rate < 5)
                    powderState = PowderState.LESS;
                else if (rate < 1)
                    powderState = PowderState.EXHAUST;
                else
                    powderState = PowderState.NORMAL;
                picPowder.Refresh();
            }
        }

        [DefaultValue(0)]
        [Description("获取或设置粉缸粉量 单位:L")]
        public float PowderCapacity
        {
            get { return powderCapacity; }
            set {
                powderCapacity = value;
                if (powderCapacity < powderQuantity)
                    powderCapacity = powderQuantity;
                picPowder.Refresh();
            }
        }

        [Browsable(false)]
        [DefaultValue(PowderState.FULL)]
        [Description("获取或设置铺粉缸的粉量状态")]
        public PowderState PowderState
        {
            get { return powderState; }
            set { powderState = value; }
        }

        [DefaultValue(500)]
        [Description("获取或设置工作缸高度")]
        public float WorkingUrnHight
        {
            get { return workingUrnHight; }
            set 
            { 
                workingUrnHight = value;
                if (workingUrnHight > workingUrnMaxHight)
                    workingUrnHight = workingUrnHight = workingUrnMaxHight;
                else if (workingUrnHight < workingUrnMinHight)
                    workingUrnHight = workingUrnMinHight;
                picWorkingUrn.Refresh();
            }
        }
        
        [DefaultValue(500)]
        [Description("获取或设置工作缸最大高度 单位:mm")]
        public float WorkingUrnMaxHight
        {
            get { return workingUrnMaxHight; }
            set
            {
                workingUrnMaxHight = value;
                if (workingUrnMaxHight < workingUrnHight)
                    workingUrnMaxHight = WorkingUrnHight;
                picWorkingUrn.Refresh();
            }
        }
        
        [DefaultValue(100)]
        [Description("获取或设置工作缸最小高度 单位:mm")]
        public float WorkingUrnMinHight
        {
            get { return workingUrnMinHight; }
            set
            {
                workingUrnMinHight = value;
                if (workingUrnMinHight < 0)
                    workingUrnMinHight = 0;
                else if (workingUrnMinHight > workingUrnHight)
                    workingUrnMinHight = workingUrnHight;
            }
        }
        
        [Description("获取或设置振镜背景颜色")]
        public Color MirrorBack
        {
            get { return mirrorBack; }
            set
            {
                mirrorBack = value;
                picMirror.Refresh();
            }
        }

        [Description("获取或设置铺粉辊背景颜色")]
        public Color RollerBack
        {
            get { return rollerBack; }
            set
            {
                rollerBack = value;
                picRoller.Refresh();
            }
        }

        [Description("获取或设置粉缸背景颜色")]
        public Color PowderBack
        {
            get { return powderBack; }
            set
            {
                powderBack = value;
                picPowder.Refresh();
            }
        }
        
        [Description("获取或设置工作缸背景颜色")]
        public Color WorkingUrnBack
        {
            get { return workingUrnBack; }
            set
            {
                workingUrnBack = value;
                picWorkingUrn.Refresh();
            }
        }

        [Browsable(false)]
        [Description("获取或设置当前层是否打印完毕")]
        public bool IsPrintFinished
        {
            get { return isPrintFinished; }
            set
            {
                isPrintFinished = value;
                if (PrintLayerFinished != null)
                    PrintLayerFinished(this);
            }
        }
        #endregion

        #region 定义委托
        public delegate void StartSpreadHandle(object sender);
        public delegate void SpreadFinishedHandle(object sender);
        public delegate void StartPrintHandler(object sender);
        public delegate void PrintLayerFinishedHandler(object sender);
        public delegate void PrintFinishedHandler(object sender);
        public delegate void PowderUseupHandler(object sender);
        public delegate void PowderFilledHandler(object sender);
        #endregion

        #region 定义事件
        /// <summary>
        /// 开始铺粉事件
        /// </summary>
        [Description("开始铺粉时触发此事件")]
        public event StartSpreadHandle StartSpread;
        /// <summary>
        /// 铺粉结束事件
        /// </summary>
        [Description("铺粉结束时触发此事件")]
        public event SpreadFinishedHandle SpreadFinished;
        /// <summary>
        /// 开始打印事件
        /// </summary>
        [Description("开始打印时触发此事件")]
        public event StartPrintHandler StartPrint;
        /// <summary>
        /// 单层打印结束事件
        /// </summary>
        [Description("当前层打印完时触发此事件")]
        public event PrintLayerFinishedHandler PrintLayerFinished;
        /// <summary>
        /// 打印结束事件
        /// </summary>
        [Description("当工件全部打印完后触发此事件")]
        public event PrintFinishedHandler PrintFinished;
        /// <summary>
        /// 粉末用完事件
        /// </summary>
        [Description("当粉末用完时触发此事件")]
        public event PowderUseupHandler PowderUseup;
        /// <summary>
        /// 粉末加满事件
        /// </summary>
        [Description("当粉末加满或添加后不影响打印时触发此事件")]
        public event PowderFilledHandler PowderFilled;
        #endregion

        #region 默认构造函数
        public PowderControl()
        {
            InitializeComponent();
        }
        #endregion

        #region 控件被加载时调用
        private void PowderControl_Load(object sender, EventArgs e)
        {
            preSize = this.Size;
            timMirror_Tick(sender, e);
            timRoller_Tick(sender, e);
            timPowder_Tick(sender, e);
            timWorkingUrn_Tick(sender, e);

            timMirror.Stop();
            timRoller.Stop();
            timPowder.Stop();
            timWorkingUrn.Stop();

            isMirrorStop = true;
            isRollerStop = true;
        }
        #endregion

        #region 控件大小调整时调用
        private void OnSizeChanged(object sender, EventArgs e)
        {
            currentSize=this.Size;
            int preMirrorBackWidth = mirrorBackWidth;
            int preRollerBackWidth = rollerBackWidth;
            if (preSize != currentSize)
            {
                if (!isSizeChangedOk)
                {
                    isSizeChangedOk = true;
                    if (this.Width < 50 || this.Height < 50)
                    {
                        this.Width = this.Height = 50;
                    }
                    else if (preSize.Height != currentSize.Height)
                    {
                        this.Width = this.Height;
                    }
                    else if (preSize.Width != currentSize.Width)
                    {
                        this.Height = this.Width;
                    }
                    else
                    {
                        this.Height = this.Width;
                    }
                }
            }
            if (isSizeChangedOk)
            {
                int height1 = this.Width * 17 / 200;
                int width1 = this.Width - 6;
                int height2 = this.Width / 4;
                if (height2 > 60)
                    height2 = 60;
                int height3 = this.Width - 6 - height1 - height2;
                int width3 = this.Width * 67 / 200;
                int width4 = this.Width - width3 - 6;

                picMirror.Width = width1; picMirror.Height = height1; picMirror.Width = width1;
                picRoller.Width = width1; picRoller.Height = height2; picRoller.Top = height1 + 3;
                picPowder.Height = height3; picPowder.Width = width3; picPowder.Top = 3 + height1 + height2;
                picWorkingUrn.Height = height3; picWorkingUrn.Width = width4; picWorkingUrn.Top = this.Width - 3 - height3; picWorkingUrn.Left = width3 + 3;

                if (this.Width < 50)
                {
                    mirrorBackWidth = picMirror.Width * 9 / 10;
                }
                else mirrorBackWidth = picMirror.Width - 10;

                rollerDiameter = height2 * 3 / 5;
                if (rollerDiameter > 40)
                    rollerDiameter = 40;
                rollerBackWidth = picRoller.Width - (int)rollerDiameter-2;

                float a = rollerLocation;
                mirrorLocation = mirrorLocation * (1.0f * mirrorBackWidth / preMirrorBackWidth);
                rollerLocation = rollerLocation * (1.0f * rollerBackWidth / preRollerBackWidth);

                this.Invalidate();
                //picMirror.Refresh();
                //picRoller.Refresh();
                //picPowder.Refresh();
                //picWorkingUrn.Refresh();
                preSize = currentSize;
                isSizeChangedOk = false;
            }
        }
        #endregion

        #region 重载控件重绘方法
        protected override void OnPaint(PaintEventArgs e)
        {
            picMirror.Refresh();
            picRoller.Refresh();
            picPowder.Refresh();
            picWorkingUrn.Refresh();
            base.OnPaint(e);
        }
        #endregion

        #region 控件重绘
        private void PowderControl_Paint(object sender, PaintEventArgs e)
        {

        }
        #endregion

        #region 振镜模块的绘制
        private void picMirror_Paint(object sender, PaintEventArgs e)
        {
            Graphics graphics = e.Graphics;
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            graphics.FillRectangle(new SolidBrush(mirrorBack), e.ClipRectangle);
            if (mirrorBackWidth <= 0)
                mirrorBackWidth = 184;
            Color colorS = System.Drawing.SystemColors.AppWorkspace;
            Color colorM = System.Drawing.SystemColors.Control;
            Color colorE = System.Drawing.SystemColors.ButtonHighlight;
            //graphics.FillRectangle(brush, rect);
            //Pen penS = new Pen(new SolidBrush(colorS), 1.0f);
            graphics.DrawLine(new Pen(new SolidBrush(colorS), 1.0f), (picMirror.Width - mirrorBackWidth) / 2, picMirror.Height / 2 - 2, (picMirror.Width + mirrorBackWidth) / 2, picMirror.Height / 2 - 2);
            graphics.DrawLine(new Pen(new SolidBrush(colorM), 2.0f), (picMirror.Width - mirrorBackWidth) / 2, picMirror.Height / 2 , (picMirror.Width + mirrorBackWidth) / 2+1, picMirror.Height / 2 );
            graphics.DrawLine(new Pen(new SolidBrush(colorE), 1.0f), (picMirror.Width - mirrorBackWidth) / 2, picMirror.Height / 2 + 1, (picMirror.Width + mirrorBackWidth) / 2, picMirror.Height / 2 + 1);

            float mw = this.Width * (7.0f / 200);
            float mh = this.Width * (14.0f / 200);
            if (mw > 8)
            {
                mw = 8.0f;
                mh = 14.0f;
            }
            else if (mw < 1.0f)
            {
                mw = 1.0f;
                mh = 2.0f;
            }
            if ((int)mirrorLocation <-10000000f)
                mirrorLocation = 0f;
            drawMirro(graphics, (picMirror.Width - mirrorBackWidth) / 2 + (int)mirrorLocation, picMirror.Height / 2, mw, mh);

            int radiu = picRoller.Width / 40;
            if (radiu > 5)
                radiu = 5;
            Rectangle rect = e.ClipRectangle;
            rect = new Rectangle(rect.X + 1, rect.Y + 1, rect.Width - 2, rect.Height - 2);
            GraphicsPath mirrorPath = gerRoundPath(rect, radiu);
            graphics.DrawPath(new Pen(new SolidBrush(Color.Gray), 2.0f), mirrorPath);
        }
        #endregion

        #region 铺粉辊的绘制
        private void picRoller_Paint(object sender, PaintEventArgs e)
        {
            Graphics graphics = e.Graphics;
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            graphics.FillRectangle(new SolidBrush(rollerBack), e.ClipRectangle);
            Color colorS = System.Drawing.SystemColors.AppWorkspace;
            Color colorE = System.Drawing.SystemColors.ButtonHighlight;
            int cx = (picRoller.Width - rollerBackWidth) / 2 + (int)rollerLocation;
            int cy = picRoller.Height*2/5;
            graphics.DrawLine(new Pen(new SolidBrush(colorS), 1.0f), cx, cy - 2, (picRoller.Width + rollerBackWidth) / 2, cy - 2);
            graphics.DrawLine(new Pen(new SolidBrush(colorE), 3.0f), cx, cy, (picRoller.Width + rollerBackWidth) / 2 + 1, cy);
            graphics.DrawLine(new Pen(new SolidBrush(colorS), 1.0f), cx, cy + 2, (picRoller.Width + rollerBackWidth) / 2, cy + 2);

            #region 画铺粉辊
            drawRoller(graphics, cx, cy);
            #endregion

            Random random = new Random();
            #region 画铺粉辊运动指示箭头
            if (rollerState != WorkState.STOP)
            {
                int a = random.Next(10);
                //3/10的概率随机绘制运动箭头
                if (a > 6)
                {
                    int arrawx = 0;
                    int arrawy = 0;
                    int arraww = 0;
                    int arrawh = 0;
                    
                    if (cx < picRoller.Width / 2)
                    {
                        arrawx = picRoller.Width * 3 / 4;
                        arrawy = cy  / 2;
                        arraww = (int)rollerDiameter / 2;
                        arrawh = (int)rollerDiameter / 4;
                        arrawy -= arrawh / 2;
                    }
                    else if (cx > picRoller.Width / 2)
                    {
                        arrawx = picRoller.Width / 4;
                        arrawy = cy / 2;
                        arraww = (int)rollerDiameter / 2;
                        arrawh = (int)rollerDiameter / 4;
                        arrawy -= arrawh / 2;
                    }
                    if (cx != picRoller.Width / 2)
                    {
                        Point []points = new Point[4];
                        Color colorA = Color.DarkSlateGray;
                        Brush brush=new SolidBrush(colorA);
                        if (rollerSpeed>0f)
                        {
                            arrawx -= (int)rollerDiameter * 7 / 12;
                            points[0].X = points[3].X = arrawx + arraww + arrawh * 3 / 2;
                            points[0].Y = points[3].Y = cy / 2;
                            points[1].X = points[2].X = arrawx + arraww;
                            points[1].Y = cy / 2 - arrawh;
                            points[2].Y = cy / 2 + arrawh;
                        }
                        else if (rollerSpeed < 0f)
                        {
                            arrawx -= (int)rollerDiameter * 1 / 12;
                            points[0].X = points[3].X = arrawx - arrawh * 3 / 2;
                            points[0].Y = points[3].Y = cy / 2;
                            points[1].X = points[2].X = arrawx;
                            points[1].Y = cy / 2 - arrawh;
                            points[2].Y = cy / 2 + arrawh;
                        }
                        graphics.FillRectangle(brush, new Rectangle(arrawx,arrawy,arraww,arrawh));
                        graphics.FillPolygon(brush, points);
                    }
                }
            }
            #endregion
            #region 画铺粉辊粉末落下动画
            Rectangle rect;
            if (rollerState == WorkState.WORK && !isPowderUseup)
            {
                int a = random.Next(4);
                //2/4的概率随机绘制粉末落下动画
                if (a > 1)
                {
                    int sx=cx-2;
                    int sy = cy + (int)rollerDiameter / 2+2;
                    int deltaX = 2;
                    int deltaY = 3;
                    
                    Brush brush=new SolidBrush(Color.Silver);
                    for (int i = 0; i < 3; i++)
                    {
                        for (int j = 0; j < 3; j++)
                        {
                            rect=new Rectangle(sx+j*deltaX,sy+i*deltaY,2,2);
                            graphics.FillEllipse(brush, rect);
                        }
                    }
                }
            }
            #endregion
            #region 画已铺粉层
            if (rollerState != WorkState.STOP && !isPowderUseup)
            {
                rect=new Rectangle(0,0,0,0);
                switch (spreadDirection)
                {
                    case SpreadPowderDirection.LEFT_TO_RIGHT:
                        if (rollerState == WorkState.WORK)
                        {
                            if ((int)rollerLocation > rollerBackWidth)
                                Console.WriteLine("l={0},w={1}",rollerLocation,rollerBackWidth);
                            rect = new Rectangle((picRoller.Width - rollerBackWidth) / 2, picRoller.Height - 6, (int)rollerLocation, 2);
                        }
                        else if (rollerState == WorkState.BACK)
                        {

                        }
                        break;
                    case SpreadPowderDirection.RIGHT_TO_LEFT:
                        if (rollerState == WorkState.WORK)
                        {
                            rect = new Rectangle((picRoller.Width - rollerBackWidth) / 2 + (int)rollerLocation, picRoller.Height - 6, rollerBackWidth-(int)rollerLocation, 2);
                        }
                        else if (rollerState == WorkState.BACK)
                        {

                        }
                        break;
                    case SpreadPowderDirection.BIDIRECTION:
                        if (rollerSpeed>0f)
                        {
                            rect = new Rectangle((picRoller.Width - rollerBackWidth) / 2, picRoller.Height - 6, (int)rollerLocation, 2);
                        }
                        else if (rollerSpeed < 0f)
                        {
                            rect = new Rectangle((picRoller.Width - rollerBackWidth) / 2 + (int)rollerLocation, picRoller.Height - 6, rollerBackWidth - (int)rollerLocation, 2);
                        }
                        break;
                }
                if(rect.Width!=0&&rect.Height!=0)
                    graphics.FillRectangle(new SolidBrush(Color.Silver), rect);
            }
            #endregion

            int radiu=picRoller.Width/30;
            if(radiu>7)
                radiu=7;
            rect = e.ClipRectangle;
            rect=new Rectangle(rect.X+1,rect.Y+1,rect.Width-2,rect.Height-2);
            GraphicsPath rollerPath = gerRoundPath(rect, radiu);
            graphics.DrawPath(new Pen(new SolidBrush(Color.Gray), 2.0f), rollerPath);

        }
        #endregion

        #region 粉缸的绘制
        private void picPowder_Paint(object sender, PaintEventArgs e)
        {
            Graphics graphics = e.Graphics;
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            Rectangle powderRect = e.ClipRectangle;
            graphics.FillRectangle(new SolidBrush(powderBack), powderRect);
            Color colorP, colorM = Color.White;

            int radiu = picPowder.Width / 10;
            if (radiu > 20)
                radiu = 20;

            #region 画当前粉量
            if (powderState == PowderState.FULL)
                colorP = Color.Silver;
            else if (powderState == PowderState.NORMAL)
                colorP = Color.Blue;
            else if (powderState == PowderState.LESS)
                colorP = Color.Red;
            else
                colorP = Color.Gray;
            int powderHight = (int)(picPowder.Height * powderQuantity / powderCapacity);
            if (powderHight > 0)
            {
                int r = radiu;
                Rectangle arcRect = new Rectangle(powderRect.Location.X, picPowder.Height - powderHight, r * 2, r * 2);
                powderRect = new Rectangle(powderRect.Location.X+1, picPowder.Height - powderHight, picPowder.Width-2, powderHight-1);
                GraphicsPath path = new GraphicsPath();
                //  左上角   
                path.AddArc(arcRect, 180, 90);
                //   上
                path.AddLine(radiu, picPowder.Height - powderHight, picPowder.Width - r * 2, picPowder.Height - powderHight);
                //  右上角   
                arcRect.X = powderRect.Right - r * 2;
                path.AddArc(arcRect, 270, 90);
                //   右
                path.AddLine(picPowder.Width, picPowder.Height - powderHight + r, picPowder.Width, picPowder.Height - 1);
                r /= 2;
                if (r == 0)
                    r = 1;
                arcRect = new Rectangle(picPowder.Width - r * 2 - 2, picPowder.Height - r * 2 - 1, r * 2, r * 2);
                //  右下角
                path.AddArc(arcRect, 0, 90);
                //   下
                path.AddLine(1, picPowder.Height - 1, picPowder.Width - 2, picPowder.Height - 1);
                arcRect.X = 1;
                //  左下角
                path.AddArc(arcRect, 90, 90);
                //   左
                path.AddLine(1, picPowder.Height - powderHight + r, 1, picPowder.Height - 1);

                LinearGradientBrush linearBrush = new LinearGradientBrush(powderRect, colorP, colorP, 90, false);
                Color[] colors = new Color[] { colorP, colorM, colorP };
                float[] positions = { 0f, 0.1f, 1.0f };
                ColorBlend blend = new ColorBlend();
                blend.Colors = colors;
                blend.Positions = positions;
                linearBrush.InterpolationColors = blend;

                graphics.FillPath(linearBrush, path);
            }
            #endregion
            #region 画粉缸外围
            radiu /= 2;
            if (radiu == 0)
                radiu = 1;
            powderRect = e.ClipRectangle;
            powderRect=new Rectangle(powderRect.X+1,powderRect.Y+1,powderRect.Width-2,powderRect.Height-2);
            GraphicsPath powderPath = gerRoundPath(powderRect, radiu);
            graphics.DrawPath(new Pen(new SolidBrush(Color.Gray), 2.0f), powderPath);
            //graphics.FillPath(new SolidBrush(Color.Gray),powderPath);
            #endregion
        }
        #endregion

        #region 工作缸的绘制
        private void picWorkingUrn_Paint(object sender, PaintEventArgs e)
        {
            Graphics graphics = e.Graphics;
            Rectangle rect = e.ClipRectangle;
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            //填充背景
            graphics.FillRectangle(new SolidBrush(workingUrnBack), rect);

            #region 绘制工作缸活动部件
            float workHeight = workingUrnHight * (1.0f * picWorkingUrn.Height / workingUrnMaxHight);
            int radiu1=picWorkingUrn.Height/20;
            if (radiu1 > 10)
                radiu1 = 10;
            rect = new Rectangle(1, (int)(picWorkingUrn.Height - workHeight)+2, picWorkingUrn.Width - 2, radiu1 * 2);
            Rectangle arcRect = new Rectangle(rect.X,rect.Y, radiu1 * 2, radiu1 * 2);
            GraphicsPath floorPath = new GraphicsPath();
            SolidBrush brush = new SolidBrush(Color.Silver);
            //工作平台为上平下圆角形状，下面一段代码为由四条直线段与两条圆弧围成绘图区
            #region 添加工作平台外轮廓路径
            floorPath.AddLine(rect.X, rect.Y, rect.X, rect.Bottom - radiu1);
            floorPath.AddLine(rect.X, rect.Y, rect.Right, rect.Y);
            floorPath.AddLine(rect.Right, rect.Y, rect.Right, rect.Bottom - radiu1);
            arcRect.X = rect.Right - 2 * radiu1;
            arcRect.Y = rect.Bottom - 2 * radiu1;
            floorPath.AddArc(arcRect, 0, 90);
            floorPath.AddLine(rect.X + radiu1, rect.Bottom, rect.Right - radiu1, rect.Bottom);
            arcRect.X = rect.X;
            floorPath.AddArc(arcRect, 90, 90);
            #endregion
            graphics.FillPath(brush, floorPath);
            #endregion

            #region 绘制工件
            int deltaH = (int)(picWorkingUrn.Height - workHeight);
            Rectangle tempRect;
            if (deltaH > 0)
            {
                brush=new SolidBrush(Color.Gray);
                if (deltaH > 3)
                {
                    int countX=picWorkingUrn.Width/3;
                    int countY=deltaH/2;
                    for (int i = 1; i < countY; i++)
                    {
                        for (int j = 1; j < countX; j++)
                        {
                            if (3 * j < picWorkingUrn.Width / 4 || 3 * j > picWorkingUrn.Width * 3 / 4)
                            {
                                tempRect = new Rectangle(3 * j, 2 * i, 2, 2);
                                graphics.FillEllipse(brush, tempRect);
                            }
                        }
                    }
                }
                brush.Color = Color.White;
                tempRect = new Rectangle(picWorkingUrn.Width / 4, 0, picWorkingUrn.Width / 2, deltaH);
                graphics.FillRectangle(brush, tempRect);
            }
            #endregion

            #region 绘制工作缸导轨
            deltaH = radiu1 / 2;//间隔高度
            int radiu2 = deltaH * 3;//黑层高度
            tempRect = new Rectangle(picWorkingUrn.Width / 2 - radiu2, rect.Bottom, radiu2 * 2, radiu2);
            brush.Color = System.Drawing.SystemColors.ControlDark;
            for (int i = 0; tempRect.Bottom < picWorkingUrn.Height; i++)
            {
                graphics.FillRectangle(brush, tempRect);
                tempRect.Y = tempRect.Y + deltaH * 4;
            }
            if (tempRect.Y < picWorkingUrn.Height)
            {
                tempRect.Height = picWorkingUrn.Height - tempRect.Y;
                graphics.FillRectangle(brush, tempRect);
            }
            #endregion

            int radiu3 =picWorkingUrn.Width/40;
            if(radiu3>10)
                radiu3=10;
            if (rect.Width < 3)
            {
                rect.Width = 3;
                rect.Height = picWorkingUrn.Height / picWorkingUrn.Width;
                if (rect.Height < 3)
                    rect.Height = 3;
            }

            #region 绘制工作缸外框
            rect = e.ClipRectangle;
            rect = new Rectangle(1, 1, rect.Width - 2, rect.Height - 2);
            GraphicsPath workingUrnPath = gerRoundPath(rect, radiu3);
            graphics.DrawPath(new Pen(new SolidBrush(Color.Gray), 2.0f), workingUrnPath);
            #endregion
        }
        #endregion

        #region 振镜开始移动
        public void startMirror()
        {
            isMirrorStop = false;
            timMirror.Start();
            if(StartPrint!=null)
                StartPrint(this);
        }
        #endregion

        #region 振镜停止移动
        public void stopMirror()
        {
            mirrorSpeed = mirrorAcc = 0f;
            isMirrorStop = true;
            mirrorState = WorkState.STOP;
            timMirror.Stop();
            
        }
        #endregion

        #region 铺粉辊开始移动
        public void startRoller()
        {
            isRollerStop = false;
            timRoller.Start();
            if (StartSpread != null)
                StartSpread(this);
            IsPrintFinished = false;
        }
        #endregion

        #region 铺粉辊停止移动
        public void stopRoller()
        {
            rollerSpeed = rollerAcc = 0f;
            isRollerStop = true;
            rollerState = WorkState.STOP;
            timRoller.Stop();
            
        }
        #endregion

        #region 绘制振镜
        /// <summary>
        /// 绘制振镜
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="sx">振镜中心x坐标</param>
        /// <param name="sy">振镜中心y坐标</param>
        /// <param name="mw">振镜宽度</param>
        /// <param name="mh">振镜高度</param>
        private void drawMirro(Graphics graphics, int sx, int sy, float mw, float mh)
        {
            float width = mw;
            float height = mh;
            PointF[] points = new PointF[6];
            //6点控制5边形振镜
            points[0] = new PointF(sx, sy + height * (8.0f / 14));
            points[1] = new PointF(sx - (int)(width / 2.0f), sy + height * (4.0f / 14));
            points[2] = new PointF(sx - (int)(width / 2.0f), sy - height * (7.0f / 14));
            points[3] = new PointF(sx + (int)(width / 2.0f), sy - height * (7.0f / 14));
            points[4] = new PointF(sx + (int)(width / 2.0f), sy + height * (4.0f / 14));
            points[5] = new PointF(sx, sy + height * (8.0f / 14));

            Rectangle rect = new Rectangle((int)(sx - width / 2), (int)(sy - height * 3 / 8), (int)width, (int)height);
            Color colorS = Color.FromArgb(252, 252, 252);
            Color colorM = Color.FromArgb(236, 236, 236);
            Color colorE = Color.FromArgb(215, 215, 215);
            Color[] colors = { colorS, colorM, colorE };
            float[] position = { 0.0f, 0.5f, 1.0f };
            ColorBlend blend = new ColorBlend();
            blend.Colors = colors;
            blend.Positions = position;
            //渐变色绘制振镜
            LinearGradientBrush brush = new LinearGradientBrush(rect, colorS, colorE, 90, false);
            brush.InterpolationColors = blend;
            try
            {
                graphics.FillPolygon(brush, points);
                graphics.DrawPolygon(new Pen(new SolidBrush(System.Drawing.SystemColors.ButtonShadow), 1.0f), points);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        #endregion

        #region 绘制铺粉辊
        /// <summary>
        /// 绘制铺粉辊
        /// </summary>
        /// <param name="graphics"></param>
        /// <param name="cx">铺粉辊中心x坐标</param>
        /// <param name="cy">铺粉辊中心y坐标</param>
        private void drawRoller(Graphics graphics, int cx, int cy)
        {
            int radiu = (int)rollerDiameter / 2;
            Rectangle rect = new Rectangle(cx - radiu, cy - radiu, (int)rollerDiameter, (int)rollerDiameter);
            graphics.FillEllipse(new SolidBrush(System.Drawing.Color.Tan), rect);
            
            #region 绘制铺粉辊小球
            radiu =radiu*2/3;
            if (radiu >= 1)
            {
                cx = cx - radiu / 2 - (int)(rollerDiameter / 3 * Math.Cos(rollerAngle));
                cy = cy - radiu / 2 - (int)(rollerDiameter / 3 * Math.Sin(rollerAngle));
                rect = new Rectangle(cx, cy, radiu, radiu);
                GraphicsPath path = new GraphicsPath();
                rect = new Rectangle(cx, cy, radiu, radiu);
                path.AddEllipse(rect);
                PathGradientBrush pthGrBrush = new PathGradientBrush(path);
                pthGrBrush.CenterColor = Color.White;
                Color[] colors = new Color[] { System.Drawing.Color.Tan };
                pthGrBrush.SurroundColors = colors;
                graphics.FillEllipse(pthGrBrush, rect);
            }
            #endregion
        }
        #endregion

        #region 运动定时器
        private void timMirror_Tick(object sender, EventArgs e)
        {
            freshMirrorLoc(0.1f);

            picMirror.Refresh();
        }

        private void timRoller_Tick(object sender, EventArgs e)
        {
            freshRollerLoc(0.1f);
            picRoller.Refresh();
        }

        private void timPowder_Tick(object sender, EventArgs e)
        {

        }

        private void timWorkingUrn_Tick(object sender, EventArgs e)
        {

        }
        #endregion

        #region 更新振镜位置、速度
        private void freshMirrorLoc(float t)
        {
            //s=s0+v*t+a*t*t/2; 计算后需将长度值转化为屏幕上的宽度值
            mirrorLocation = mirrorLocation+(mirrorSpeed * t + mirrorAcc * t * t / 2)*(float)mirrorBackWidth/mirrorMaxH;
            //v=v0+a*t;
            MirrorSpeed = mirrorSpeed + mirrorAcc * t;
            if (mirrorLocation > (int)mirrorBackWidth || mirrorLocation < 0f)
            {
                mirrorSpeed *= -1;
                if (mirrorState == WorkState.WORK)
                {
                    IsPrintFinished = true;
                }
            }
        }
        #endregion

        #region 更新铺粉辊位置、速度
        private void freshRollerLoc(float t)
        {
            float deltaS = rollerSpeed * t + rollerAcc * t * t / 2;
            rollerLocation = rollerLocation + deltaS * (float)rollerBackWidth / RollerMax;
            RollerSpeed = rollerSpeed + rollerAcc * t;
            if (rollerLocation > (int)rollerBackWidth || rollerLocation<0f)
            {
                rollerSpeed *= -1;
            }
            rollerAngle = 2 * Math.PI * (rollerLocation / (rollerDiameter*Math.PI));
        }
        #endregion

        #region 计算粉缸剩余粉量
        private void freshPowderQuantity()
        {
            if (!isPowderUseup)
            {
                float deltaPowder = powderWidth * powderLength * powderPly / 1000000f;
                PowderQuantity -= deltaPowder;
                if (powderQuantity * 1.0f / PowderCapacity < 0.01)
                {
                    isPowderUseup = true;
                    if (PowderUseup != null)
                        PowderUseup(this);
                }
            }
        }
        #endregion
        
        #region 计算粉缸剩余粉量
        private void freshWorkingUrn()
        {
            workingUrnHight -= powderPly;
            picWorkingUrn.Refresh();
            if (SpreadFinished != null)
                SpreadFinished(this);
            if (Math.Abs(workingUrnHight - workingUrnMinHight) / workingUrnMinHight < 0.0001f && IsPrintFinished)
            {
                if (PrintFinished != null)
                    PrintFinished(this);
            }
        }
        #endregion

        #region 获取圆角矩形路径
        private GraphicsPath gerRoundPath(Rectangle rect,int radiu)
        {
            if (radiu < 1)
                radiu = 1;
            if (rect.Width < 2 * radiu)
                rect.Width = 2 * radiu;
            if (rect.Height < 2 * radiu)
                rect.Height = 2 * radiu;
            Rectangle arcRect = new Rectangle(rect.Location, new Size(radiu * 2, radiu * 2));
            GraphicsPath arcPath = new GraphicsPath();
            //   左上角   
            arcPath.AddArc(arcRect, 180, 90);
            //   上
            arcPath.AddLine(rect.X + radiu, rect.Y, rect.X + rect.Width - radiu, rect.Y);
            //   右上角   
            arcRect.X = rect.Right - radiu * 2;
            arcPath.AddArc(arcRect, 270, 90);
            //   右
            arcPath.AddLine(rect.Right, rect.Y + radiu, rect.Right, rect.Bottom - radiu);
            //   右下角   
            arcRect.Y = rect.Bottom - radiu * 2;
            arcPath.AddArc(arcRect, 0, 90);
            //   下
            arcPath.AddLine(rect.X + radiu, rect.Bottom, rect.X + rect.Width - radiu, rect.Bottom);
            //   左下角   
            arcRect.X = rect.X;
            arcPath.AddArc(arcRect, 90, 90);
            //   左
            arcPath.AddLine(rect.X, rect.Y + radiu, rect.X, rect.Bottom - radiu);
            return arcPath;
        }
        #endregion
    }
    #region 枚举状态
    /// <summary>
    /// 停止，工作，后退
    /// </summary>
    public enum WorkState
    {
        WORK, BACK, STOP
    }
    /// <summary>
    /// 满，正常，极少，耗尽
    /// </summary>
    public enum PowderState
    {
        FULL,NORMAL,LESS,EXHAUST
    }
    /// <summary>
    /// 左向右，右向左，双向
    /// </summary>
    public enum SpreadPowderDirection
    {
        LEFT_TO_RIGHT,RIGHT_TO_LEFT,BIDIRECTION
    }
    #endregion
}